use sea_orm::{
    ActiveModelTrait, ColumnTrait, DatabaseConnection, DbErr, EntityTrait, 
    IntoActiveModel, QueryFilter, QueryOrder, Set
};
use chrono::Utc;
use ulid::Ulid;
use crate::models::user::{Model as User, SafeUser, Entity as UserEntity};
use crate::utils::hash_password;

pub struct UserService;

impl UserService {
    pub async fn create(
        db: &DatabaseConnection,
        username: &str,
        password: &str,
        avatar: &str,
        introduction: &str,
        tenant_id: Option<i64>
    ) -> Result<User, DbErr> {
        let now = Utc::now().naive_utc();
        let user = crate::models::user::ActiveModel {
            id: Set(0), // TODO: Replace with proper ID generation
            username: Set(username.to_string()),
            password: Set(hash_password(password).map_err(|e| DbErr::Custom(e.to_string()))?),
            avatar: Set(avatar.to_string()),
            introduction: Set(introduction.to_string()),
            create_by: Set("admin".to_string()),
            create_time: Set(now),
            update_by: Set("admin".to_string()),
            update_time: Set(now),
            tenant_id: Set(tenant_id.unwrap_or(0)),
            ..Default::default()
        };

        user.insert(db).await
    }

    pub async fn update(
        db: &DatabaseConnection,
        id: &i64,
        username: Option<&str>,
        password: Option<&str>,
        avatar: Option<&str>,
        introduction: Option<&str>,
        tenant_id: Option<i64>
    ) -> Result<User, DbErr> {
        let mut user = UserEntity::find_by_id(id)
            .one(db)
            .await?
            .ok_or(DbErr::RecordNotFound("User not found".to_string()))?
            .into_active_model();

        if let Some(username) = username {
            user.username = Set(username.to_string());
        }
        if let Some(password) = password {
            user.password = Set(hash_password(password).map_err(|e| DbErr::Custom(e.to_string()))?);
        }
        if let Some(avatar) = avatar {
            user.avatar = Set(avatar.to_string());
        }
        if let Some(introduction) = introduction {
            user.introduction = Set(introduction.to_string());
        }
        user.update_by = Set("admin".to_string());
        user.update_time = Set(Utc::now().naive_utc());

        user.update(db).await
    }

    pub async fn delete(
        db: &DatabaseConnection,
        id: &i64,
        tenant_id: Option<i64>
    ) -> Result<u64, DbErr> {
        let res = UserEntity::delete_many()
            .filter(crate::models::user::Column::Id.eq(id))
            .filter(crate::models::user::Column::TenantId.eq(tenant_id))
            .exec(db)
            .await?;

        Ok(res.rows_affected)
    }

    pub async fn find_by_id(
        db: &DatabaseConnection,
        id: i64,
        tenant_id: Option<i64>
    ) -> Result<Option<User>, DbErr> {
        UserEntity::find()
            .filter(crate::models::user::Column::Id.eq(id))
            .filter(crate::models::user::Column::TenantId.eq(tenant_id))
            .one(db)
            .await
    }

    pub async fn find_by_username(
        db: &DatabaseConnection,
        username: &str,
        tenant_id: Option<i64>
    ) -> Result<Option<User>, DbErr> {
        UserEntity::find()
            .filter(crate::models::user::Column::Username.eq(username))
            .filter(crate::models::user::Column::TenantId.eq(tenant_id))
            .one(db)
            .await
    }

    pub async fn find_all(
        db: &DatabaseConnection,
        username_filter: Option<&str>,
        tenant_id: Option<i64>,
        page: u64,
        page_size: u64
    ) -> Result<(Vec<SafeUser>, u64), DbErr> {
        let mut query = UserEntity::find()
            .filter(crate::models::user::Column::TenantId.eq(tenant_id));

        if let Some(filter) = username_filter {
            query = query.filter(crate::models::user::Column::Username.contains(filter));
        }

        let total = query.clone().count(db).await?;
        let users = query
            .order_by_asc(crate::models::user::Column::CreateTime)
            .offset((page - 1) * page_size)
            .limit(page_size)
            .all(db)
            .await?;

        Ok((users.into_iter().map(|u| SafeUser {
            id: u.id,
            username: u.username,
            avatar: u.avatar,
            introduction: u.introduction,
            create_by: u.create_by,
            create_time: u.create_time,
            update_by: u.update_by,
            update_time: u.update_time,
            tenant_id: u.tenant_id,
        }).collect(), total))
    }
}
